// Package repository internal/repository/menu_repository.go
package repository

import (
	"errors"
	"gorm.io/gorm"
	"gozrd-admin-api/internal/entity/model"
	"time"
)

var (
	MenuExist    = errors.New("菜单名称已存在")
	MenuAssigned = errors.New("菜单已分配角色，无法删除")
)

// IMenuRepository 菜单仓库接口
type IMenuRepository interface {
	GetSysMenuByName(menuName string) (model.Menu, error)
	CreateSysMenu(menu model.Menu) error
	GetSysMenu(id int) (model.Menu, error)
	UpdateSysMenu(menu model.Menu) (model.Menu, error)
	DeleteSysMenu(id int) error
	GetSysMenuList(menuName string, menuStatus string) ([]model.Menu, error)
	IsSysMenuAssigned(id int) (bool, error)
	QueryMenuByAdminAndParent(adminId int, parentId int) ([]model.Menu, error)
	QueryMenuByAdmin(adminId int) ([]model.Menu, error)
	QueryPermissionsByAdminId(adminId int) ([]string, error)
}

// MenuRepository 菜单仓库实现
type MenuRepository struct {
	db *gorm.DB
}

// NewMenuRepository 创建菜单仓库
func NewMenuRepository(db *gorm.DB) IMenuRepository {
	return &MenuRepository{
		db: db,
	}
}

// GetSysMenuByName 根据菜单名称查询
func (r *MenuRepository) GetSysMenuByName(menuName string) (model.Menu, error) {
	var menu model.Menu
	err := r.db.Where("menu_name = ?", menuName).First(&menu).Error
	return menu, err
}

// CreateSysMenu 新增菜单
func (r *MenuRepository) CreateSysMenu(menu model.Menu) error {
	// 检查菜单名称是否已存在
	existingMenu, err := r.GetSysMenuByName(menu.MenuName)
	if err != nil && err != gorm.ErrRecordNotFound {
		return err
	}
	if existingMenu.ID != 0 {
		return MenuExist
	}

	// 设置创建时间
	now := time.Now()
	menu.CreateTime = &now

	// 处理目录类型菜单的特殊逻辑
	if menu.MenuType == 1 {
		menu.ParentID = nil
	}

	// 创建菜单
	return r.db.Create(&menu).Error
}

// GetSysMenu 根据id查询菜单详情
func (r *MenuRepository) GetSysMenu(id int) (model.Menu, error) {
	var menu model.Menu
	err := r.db.First(&menu, id).Error
	return menu, err
}

// UpdateSysMenu 修改菜单
func (r *MenuRepository) UpdateSysMenu(menu model.Menu) (model.Menu, error) {
	// 使用事务确保原子性
	tx := r.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 查询菜单是否存在
	var existingMenu model.Menu
	if err := tx.First(&existingMenu, menu.ID).Error; err != nil {
		tx.Rollback()
		return model.Menu{}, err
	}

	// 更新字段
	existingMenu.ParentID = menu.ParentID
	existingMenu.MenuName = menu.MenuName
	existingMenu.Icon = menu.Icon
	existingMenu.Value = menu.Value
	existingMenu.MenuType = menu.MenuType
	existingMenu.URL = menu.URL
	existingMenu.MenuStatus = menu.MenuStatus
	existingMenu.Sort = menu.Sort

	// 保存更改
	if err := tx.Save(&existingMenu).Error; err != nil {
		tx.Rollback()
		return model.Menu{}, err
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		return model.Menu{}, err
	}

	return existingMenu, nil
}

// IsSysMenuAssigned 检查菜单是否被分配给角色
func (r *MenuRepository) IsSysMenuAssigned(id int) (bool, error) {
	var count int64
	err := r.db.Table("sys_role_menu").Where("menu_id = ?", id).Count(&count).Error
	return count > 0, err
}

// DeleteSysMenu 删除菜单
func (r *MenuRepository) DeleteSysMenu(id int) error {
	// 使用事务确保原子性
	tx := r.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 检查菜单是否已分配角色
	assigned, err := r.IsSysMenuAssigned(id)
	if err != nil {
		tx.Rollback()
		return err
	}
	if assigned {
		tx.Rollback()
		return MenuAssigned
	}

	// 删除子菜单
	if err := tx.Where("parent_id = ?", id).Delete(&model.Menu{}).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 删除菜单
	if err := tx.Delete(&model.Menu{}, id).Error; err != nil {
		tx.Rollback()
		return err
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		return err
	}

	return nil
}

// GetSysMenuList 查询菜单列表
func (r *MenuRepository) GetSysMenuList(menuName string, menuStatus string) ([]model.Menu, error) {
	var menus []model.Menu
	db := r.db.Order("sort")

	if menuName != "" {
		db = db.Where("menu_name = ?", menuName)
	}
	if menuStatus != "" {
		db = db.Where("menu_status = ?", menuStatus)
	}

	err := db.Find(&menus).Error
	return menus, err
}

// QueryMenuByAdminAndParent 查询 当前登录用户特定父级下 的菜单 当前登录用户左侧菜单级列表
func (r *MenuRepository) QueryMenuByAdminAndParent(adminId int, parentId int) ([]model.Menu, error) {
	var menus []model.Menu

	err := r.db.Table("sys_menu").
		Select("sys_menu.*").
		Joins("LEFT JOIN sys_role_menu ON sys_menu.id = sys_role_menu.menu_id").
		Joins("LEFT JOIN sys_role ON sys_role.id = sys_role_menu.role_id").
		Joins("LEFT JOIN sys_admin_role ON sys_admin_role.role_id = sys_role.id").
		Joins("LEFT JOIN sys_admin ON sys_admin.id = sys_admin_role.admin_id").
		Where("sys_role.status = ?", 1).
		Where("sys_menu.menu_status = ?", 2).
		Where("sys_menu.menu_type = ?", 2).
		Where("sys_menu.parent_id = ?", parentId).
		Where("sys_admin.id = ?", adminId).
		Order("sys_menu.sort").
		Find(&menus).Error

	return menus, err
}

// QueryMenuByAdmin 查询当前登录用户的 左侧 菜单列表
func (r *MenuRepository) QueryMenuByAdmin(adminId int) ([]model.Menu, error) {
	var menus []model.Menu

	err := r.db.Table("sys_menu").
		Select("sys_menu.*").
		Joins("LEFT JOIN sys_role_menu ON sys_role_menu.menu_id = sys_menu.id").
		Joins("LEFT JOIN sys_role ON sys_role.id = sys_role_menu.role_id").
		Joins("LEFT JOIN sys_admin_role ON sys_admin_role.role_id = sys_role.id").
		Joins("LEFT JOIN sys_admin ON sys_admin.id = sys_admin_role.admin_id").
		Where("sys_role.status = ?", 1).
		Where("sys_menu.menu_status = ?", 2).
		Where("sys_menu.menu_type = ?", 1).
		Where("sys_admin.id = ?", adminId).
		Order("sys_menu.sort").
		Find(&menus).Error

	return menus, err
}

// QueryPermissionsByAdminId 查询当前登录用户的权限列表
func (r *MenuRepository) QueryPermissionsByAdminId(adminId int) ([]string, error) {
	var values []string

	err := r.db.Table("sys_menu").
		Select("sys_menu.value").
		Joins("LEFT JOIN sys_role_menu ON sys_menu.id = sys_role_menu.menu_id").
		Joins("LEFT JOIN sys_role ON sys_role.id = sys_role_menu.role_id").
		Joins("LEFT JOIN sys_admin_role ON sys_admin_role.role_id = sys_role.id").
		Joins("LEFT JOIN sys_admin ON sys_admin.id = sys_admin_role.admin_id").
		Where("sys_role.status = ?", 1).
		Where("sys_menu.menu_status = ?", 2).
		Not("sys_menu.menu_type = ?", 1).
		Where("sys_admin.id = ?", adminId).
		Where("sys_menu.value != ''").
		Pluck("sys_menu.value", &values).Error

	return values, err
}
